package com.though.weixin.soa;

import com.though.http.method.Post;
import com.though.http.soa.HttpInvoker;
import com.though.weixin.base.WeixinException;
import com.though.weixin.config.PayConfg;
import com.though.weixin.params.PayOrderParams;
import com.though.weixin.params.PayRefundParams;
import com.though.weixin.params.SendRedPackParams;
import com.though.weixin.utils.PayHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Map;
import java.util.SortedMap;

@SuppressWarnings("deprecation")
public class WeixinPay {

	private static final Logger logger = LoggerFactory.getLogger(WeixinPay.class);
	
	private static PayConfg config = new PayConfg();
	
	
	/**
	 * 获取预支付订单
	 */
	public static String payOrder(PayOrderParams params) {
		// 添加额外数据
		SortedMap<String, String> paramsMap = PayHelper.createRequestPayParams(params, config.getConfigParams());
		// 生产签名
		PayHelper.sign(paramsMap, config.getConfigParams().getSign_key());
		// 生产成xml
		String xml = PayHelper.mapToXML(paramsMap);
		logger.info("Weixin pay request params:{}", paramsMap);
		
		Post post = new Post(config.getConfigParams().getBase_url() + "/pay/unifiedorder");
		post.setEntity(new StringEntity(xml, "UTF-8"));
		
		String text = null;
		try {
			text = HttpInvoker.execute(post).getBody();
		} catch (Exception e) {
			logger.error("Weixin pay invoker error params:", e);
			throw new WeixinException("调取微信支付异常！");
		}
		
		if (StringUtils.isBlank(text)) throw new WeixinException("调取微信支付返回数据为空！");
		
		logger.info("Weixin pay request response:{}", text);
		
		Map<String, String> data = PayHelper.doXMLParse(text);
		if (!data.get("return_code").equals("SUCCESS")) throw new WeixinException(data.get("return_msg"));
		if (!data.get("result_code").equals("SUCCESS")) throw new WeixinException(data.get("err_code_des"));
		
		// 返回调用的数据

		return PayHelper.appInvokerData(data.get("prepay_id"), config.getConfigParams(),params.getTrade_type());
	}
	
	
	/**
	 * 退款
	 * 需要双向证书
	 */
	public static Map<String, String> payRefund(PayRefundParams params) throws Exception {

		// 添加额外数据
		SortedMap<String, String> paramsMap = PayHelper.createRequestRefundParams(params, config.getConfigParams());
		// 生产签名
		PayHelper.sign(paramsMap, config.getConfigParams().getSign_key());
		// 生产成xml
		String xml = PayHelper.mapToXML(paramsMap);
		logger.info("Weixin refund request params:{}", paramsMap);
		
		HttpPost httppost = new HttpPost(config.getConfigParams().getBase_url() + "/secapi/pay/refund");
        httppost.setEntity(new StringEntity(xml, "UTF-8"));

		String text = null;
		try {
			text = EntityUtils.toString(getHttpClient().execute(httppost).getEntity());
		} catch (Exception e) {
			logger.error("Weixin refund invoker error params:", e);
			throw new WeixinException("调取微信退款异常！");
		}
		
		if (StringUtils.isBlank(text)) throw new WeixinException("调取微信退款返回数据为空！");
		
		logger.info("Weixin refund request response:{}", text);
		
		Map<String, String> data = PayHelper.doXMLParse(text);
		if (!data.get("return_code").equals("SUCCESS")) throw new WeixinException(data.get("return_msg"));
		if (!data.get("result_code").equals("SUCCESS")) throw new WeixinException(data.get("err_code_des"));
		
		return data;
	}

	public static Map<String, String> sendRedPack(SendRedPackParams params){
        // 添加额外数据
        SortedMap<String, String> paramsMap = PayHelper.createRequestSendRedPack(params, config.getConfigParams());
        // 生产签名
        PayHelper.sign(paramsMap, config.getConfigParams().getSign_key());
        // 生产成xml
        String xml = PayHelper.mapToXML(paramsMap);
        logger.info("Weixin send red pack request params:{}", paramsMap);

        HttpPost httppost = new HttpPost(config.getConfigParams().getBase_url() + "/mmpaymkttransfers/sendredpack");
        httppost.setEntity(new StringEntity(xml, "UTF-8"));

        String text = null;
        try {
            text = EntityUtils.toString(getHttpClient().execute(httppost).getEntity());
        } catch (Exception e) {
            logger.error("Weixin send red pack invoker error params:", e);
            throw new WeixinException("调取微信发红包异常！");
        }

        if (StringUtils.isBlank(text)) throw new WeixinException("调取微信发红包返回数据为空！");

        logger.info("Weixin send red pack request response:{}", text);
        Map<String, String> data = PayHelper.doXMLParse(text);
        if (!data.get("return_code").equals("SUCCESS")) throw new WeixinException(data.get("return_msg"));
        if (!data.get("result_code").equals("SUCCESS")) throw new WeixinException(data.get("err_code_des"));

        return data;
    }

    private static CloseableHttpClient getHttpClient() throws Exception{
        KeyStore keyStore  = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File(config.getConfigParams().getApiclient_cert()));
        try {
            //证书密码默认为商户号
            keyStore.load(instream, config.getConfigParams().getMch_id().toCharArray());
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, config.getConfigParams().getMch_id().toCharArray())
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[] { "TLSv1" },
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .setUserAgent("Apache-HttpClient")
                .build();
        return httpclient;
    }
}